﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using MoneyManagerNET.Presentation.Infrastructure.Binding;
using System.Linq.Expressions;
using System.Collections;
using System.Collections.Specialized;

namespace MoneyManagerNET.Presentation.ViewModel.Base
{
    public class ViewModelBase : NotifyProp,IViewModel, IDataErrorInfo
    {
        #region [change notification]
        //to inject Notifyable function into domain objects
        public WrapConverter Wrapper { get; protected set; }

        public ViewModelBase()
        {
            this.Wrapper = new WrapConverter();
            identityMap = this.Wrapper.identityMap;//TODO: this uses global , switch to local
        }

        //notifyable wrappers . NOTE implement weak reference like in PropertyChangedEventManager
        protected Hashtable identityMap = new Hashtable();


        protected void RaiseCollectionChanged(object contragent)
        {
            var notifyable=(identityMap[contragent] as INotifyableCollection);
            if(notifyable!=null)
                notifyable.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        }

        protected void RaisePropertyChanged(object contragent, string p)
        {
            var notifyable = identityMap[contragent] as INotifyable;
            if(notifyable!=null)
                notifyable.OnChange(p);
        }
        #endregion


        object _model;
        public virtual object Model
        {
            get
            {
                return _model;
            }
            set
            {
                _model = value; 
                OnChange(""); 
                this.OnChange(() => Model);
            }
        }

        public virtual Type GetModelType()
        {
            return (Model == null) ? null : Model.GetType();
        }

        public virtual void LoadValues() { }
        public virtual object PutValues() { return Model; }



        #region [VALIDATION] IDataErrorInfo 

        public bool IsValid { get { return string.IsNullOrEmpty(Error); } }
        public string Error
        {
            get { return string.Join(" ; ", _Errors.Values.Cast<string>().ToArray().Where(str=>!string.IsNullOrEmpty(str))); }
        }

        Dictionary<string, string> _Errors = new Dictionary<string, string>();
        public string this[string columnName]
        {
            get { return _Errors[columnName]; }
        }

        protected string this[Expression<Func<object>> property]
        {
            set
            {
                var propName=BindingExtensions.Expression2PropertyName(property);
                _Errors[propName] = value;
                this.OnChange(() => Error);
            }
        }

        //TODO: Rule list, a dictionary to attach rules for each property

        #endregion


        protected virtual void RefreshCommandStatuses() { }

    }

}
